import GCBlock from "../../components/common-components/GCBlock";
import GCToast from "../../components/common-components/GCToast";
import GameLogic from "../../GameLogic";
import { GCAnalytics } from "../../GCAnalytics";
import GCConnection, { GameMode } from "../../GCConnection";
import GCGlobal from "../../GCGlobal";
import { QuestionResponse, SettleResponse, AnswerResponse } from "../../model/model-game";
import GCState from "../GCState";

export class GameState extends GCState {
    questionIdx = -1;

    questionList: QuestionResponse[] = [];

    mode: GameMode;

    async enter(logic: GameLogic) {
        logic.header.backNode.active = false;

        GCBlock.block();

        try {
            const resp = await GCConnection.startGame(this.mode);

            if (resp.cost) {
                GCGlobal.Account.hearts -= resp.cost;
                logic.header.updateHearts(GCGlobal.Account.hearts);
            }

            GCAnalytics.onStarted();
        } catch (e) {
            cc.error(e);
            GCToast.toast(e.message);
            logic.sm.to('menu');

            GCAnalytics.onFailed(e.message);
            return;
        } finally {
            GCBlock.unblock();
        }

        this.questionIdx = 0;
        await this.getNextQuestion(logic);
    }

    exit(logic: GameLogic): void {
        this.questionIdx = -1;
        this.questionList.length = 0;
    }

    async process(logic: GameLogic, type: string, answer?: any) {

        if (type === 'answer') {
            this.processAnswer(logic, answer);
        } else if (type === 'collect') {
            this.processCollect(logic);
        }

    }

    protected async gameOver(logic: GameLogic) {
        GCBlock.block();
        let resp: SettleResponse = null;

        try {
            resp = await GCConnection.settleGame();
        } catch (e) {

            cc.error(e);
            GCToast.toast('Settle Game Failed');

            GCAnalytics.onFailed(e.message);

            await logic.sleep(100);
            logic.sm.to('menu');

            return;
        } finally {
            GCBlock.unblock();
        }

        GCGlobal.Account.hearts += resp.hearts;
        logic.classicComp.resultWnd.initUI(resp.hearts);
        logic.classicComp.resultWnd.showWnd();

        GCAnalytics.onSuccess(resp.hearts);
    }

    protected async processCollect(logic: GameLogic) {
        const pos = logic.header.getHeartPosInWorld();
        logic.classicComp.resultWnd.doCollect(pos, () => {

            logic.classicComp.resultWnd.closeWind();
            logic.header.updateHearts(GCGlobal.Account.hearts);
            logic.sm.to('menu');

        });
    }

    protected answerMap = { A: 0, B: 1, C: 2, D: 3 };

    protected async processAnswer(logic: GameLogic, answer: string) {
        GCBlock.block();

        const question = this.questionList[this.questionIdx];
        answer = question.options[this.answerMap[answer]];

        let resp: AnswerResponse = null;
        try {
            resp = await GCConnection.requestAnswer(question.id, answer);

            logic.classicComp.resultTip.tip(!!resp.right, resp.right ? 'Perfect' : 'Opps');

        } catch (e) {
            cc.error(e);

            GCToast.toast(e.message);
            GCAnalytics.onFailed(e.message);

            logic.sm.to('menu');
            return;
        } finally {
            GCBlock.unblock();
        }

        // 展示答案
        await logic.sleep(500);

        if (resp.isLast) {
            // 结算
            this.gameOver(logic);
            return;
        }

        // 准备下一题目
        await logic.classicComp.moveToLeft();
        this.questionIdx++;
        await this.getNextQuestion(logic);
        await logic.classicComp.moveToRight();
    }

    protected async getNextQuestion(logic: GameLogic) {
        GCBlock.block();
        try {

            const resp = await GCConnection.requestQuestion(null);
            this.questionList.push(resp);
            logic.classicComp.initUI(resp.pic, resp.options);

        } catch (e) {
            cc.error(e);

            GCToast.toast(e.message);
            GCAnalytics.onFailed(e.message);

            logic.sm.to('menu');
            return;
        } finally {
            GCBlock.unblock();
        }
    }
}
